/**
 * Copyright &copy; 2017-2019 <a href="https://gitee.com/baseweb/JSite">JSite</a> All rights reserved.
 */
package com.jsite.modules.flowable.web;

import com.google.common.collect.Maps;
import com.jsite.common.config.Global;
import com.jsite.common.lang.StringUtils;
import com.jsite.common.persistence.Page;
import com.jsite.common.web.BaseController;
import com.jsite.modules.file.service.SysFileService;
import com.jsite.modules.flowable.entity.*;
import com.jsite.modules.flowable.service.*;
import com.jsite.modules.flowable.utils.FlowableUtils;
import com.jsite.modules.flowable.utils.FormUtils;
import com.jsite.modules.sys.entity.Dict;
import com.jsite.modules.sys.service.DictService;
import com.jsite.modules.sys.utils.UserUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 流程表单生成Controller
 * @author liuruijun
 * @version 2019-03-21
 */
@Controller
@RequestMapping(value = "${adminPath}/act/flowForm")
public class FlowFormController extends BaseController {

    @Autowired
    private RuntimeService runtimeService;

	@Autowired
	private FlowFormService flowFormService;

	@Autowired
    private DeModelService deModelService;

	@Autowired
    private FlowFormAuthorizeService authorizeService;

	@Autowired
    private FlowFormVarsService varsService;

    @Autowired
    private DictService dictService;

	@Autowired
	private FlowTaskService actTaskService;

    @Autowired
    private FormDataService formDataService;

    @Autowired
    private FlowFormBusinessService businessService;

    @Autowired
    private SysFileService fileService;

	@ModelAttribute
	public FlowForm get(@RequestParam(required=false) String id) {
		FlowForm entity = null;
		if (StringUtils.isNotBlank(id)){
			entity = flowFormService.get(id);
		}
		if (entity == null){
			entity = new FlowForm();
		}
		return entity;
	}
	
	@RequiresPermissions("flowable:flowForm:view")
	@RequestMapping(value = {"list", ""})
	public String list() {
		return "modules/flow/flowFormList";
	}
	
	@RequiresPermissions("flowable:flowForm:view")
	@RequestMapping(value = "listData")
	@ResponseBody
	public Page<FlowForm> listData(FlowForm flowForm, HttpServletRequest request, HttpServletResponse response) {
		Page<FlowForm> page = flowFormService.findPage(new Page<>(request, response), flowForm);
		return page;
	}

    /**
     * 获取流程 发起流程列表
     */
    @RequestMapping(value = "process")
    public String processList() {
        return "modules/flow/flowTaskProcessList";
    }

    /**
     * 获取流程列表
     * @param category 流程分类
     */
    @RequestMapping(value = "processDataList")
    @ResponseBody
    public List<ReProcDef>  processDataList(String category) {
        return flowFormService.processList(category);
    }

	@RequiresPermissions("flowable:flowForm:view")
	@RequestMapping(value = "form")
	public String form(FlowForm flowForm, Model model) {
		model.addAttribute("flowForm", flowForm);
		return "modules/flow/flowFormForm";
	}

	@RequiresPermissions("flowable:flowForm:edit")
	@RequestMapping(value = "save")
	@ResponseBody
	public String save(FlowForm flowForm) {
        if(Global.isDemoMode()){
            return renderResult(Global.FALSE, "演示模式，不允许操作！");
        }
        FlowForm tmp = flowFormService.getEntity(flowForm);
        if (tmp != null) {
            flowForm.setId(tmp.getId());
        }
		flowFormService.save(flowForm);
		return renderResult(Global.TRUE, "保存流程表单信息成功");
	}
	
	@RequiresPermissions("flowable:flowForm:edit")
	@RequestMapping(value = "delete")
	@ResponseBody
	public String delete(FlowForm flowForm) {
        if(Global.isDemoMode()){
            return renderResult(Global.FALSE, "演示模式，不允许操作！");
        }
		flowFormService.delete(flowForm);
		return renderResult(Global.TRUE, "删除流程表单信息成功");
	}

	//复制增加流程表单版本信息
    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "copy")
    @ResponseBody
    public String copy(FlowForm flowForm) {
        if(Global.isDemoMode()){
            return renderResult(Global.FALSE, "演示模式，不允许操作！");
        }
        //复制表单并增加版本号保存
        FlowForm  copies = new FlowForm();
        copies.setModelVersion(String.valueOf(Integer.valueOf(flowForm.getModelVersion())+1));
        copies.setModelId(flowForm.getModelId());
        copies.setModelKey(flowForm.getModelKey());
        copies.setFormContent(flowForm.getFormContent());

        // 获取数据权限
        List<TaskNode> taskNodeList = authorizeService.findList(new TaskNode(flowForm.getModelKey(), flowForm.getModelVersion()));

        //保存表单数据权限
        for (TaskNode taskNode: taskNodeList ) {
            TaskNode temp = new TaskNode(taskNode);
            temp.setModelVersion(String.valueOf(Integer.valueOf(flowForm.getModelVersion())+1));
            temp.setResourceId(taskNode.getResourceId());
            temp.setResourceName(taskNode.getResourceName());
            temp.setIsHide(taskNode.getIsHide());
            temp.setIsRead(taskNode.getIsRead());
            authorizeService.save(temp);
        }

        // 保存流程变量
        List<TaskNode> varNodeList = varsService.findList(new TaskNode(flowForm.getModelKey(), flowForm.getModelVersion()));
        for (TaskNode varNode : varNodeList) {
            TaskNode temp = new TaskNode(varNode);
            temp.setModelVersion(String.valueOf(Integer.valueOf(flowForm.getModelVersion())+1));
            temp.setVarName(varNode.getVarName());
            varsService.save(temp);
        }

        flowFormService.save(copies);

        return renderResult(Global.TRUE, "复制增加流程表单版本信息成功");
    }

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "content")
    @ResponseBody
    public String content(FlowForm flowForm) {
        FlowForm content = flowFormService.getEntity(flowForm);
        return renderResult(Global.TRUE, "获取流程表单信息成功", content);
    }

	@RequiresPermissions("flowable:flowForm:view")
	@RequestMapping(value = "authorize")
	public String authorize(FlowForm flowForm, Model model, String fieldName) {

        DeModel deModel = deModelService.get(flowForm.getModelId());
        List<TaskNode> taskNodeList = authorizeService.authorizeNodeList(deModel.getModelEditorJson(), flowForm, fieldName);
        TaskNode selectVar = varsService.bindVar(flowForm, fieldName);
        model.addAttribute("fieldAuthorize", new FieldAuthorize(fieldName, (selectVar==null?"":selectVar.getVarName()), taskNodeList));

        List<String> varList = varsService.varsNodeList(deModel.getModelEditorJson());
        model.addAttribute("varList", varList);

        return "modules/flow/flowFormAuthorize";
	}

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "saveAuthroize")
    @ResponseBody
    public String saveAuthroize(FieldAuthorize fieldAuthorize) {
        if(Global.isDemoMode()){
            return renderResult(Global.FALSE, "演示模式，不允许操作！");
        }
        for (TaskNode node : fieldAuthorize.getTaskNodeList()){
//            authorizeService.deleteByFieldAndKeyVersion(node);
            authorizeService.save(node);
        }

        if (StringUtils.isNotBlank(fieldAuthorize.getVarName())) {
            TaskNode varNode = new TaskNode(fieldAuthorize.getTaskNodeList().get(0));
            varNode.setVarName(fieldAuthorize.getVarName());
            varsService.saveUpdate(varNode);
        }

        return renderResult(Global.TRUE, "保存成功");
    }

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "dictList")
    @ResponseBody
    public String dictList(String type) {
        List<Dict> dicts;
	    if (StringUtils.isBlank(type)) {
            dicts = dictService.findListGroupByType();
        } else {
            Dict dict = new Dict();
            dict.setType(type);
            dicts = dictService.findList(dict);
        }

        return renderResult(Global.TRUE, "获取成功", dicts);
    }

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "preview")
    public String preview(FlowForm flowForm, Model model) {
        // 获取数据权限信息
        List<TaskNode> taskNodeList = authorizeService.findList(new TaskNode(flowForm.getModelKey(), flowForm.getModelVersion()));
        if (taskNodeList == null) {
            model.addAttribute("message", "请先去完成表单字段权限设置！");
            return "modules/flow/flowFormError";
        }
        String formContent = FormUtils.parseForm(flowForm.getFormContent(), null, taskNodeList, "finish");
	    model.addAttribute("formContent", formContent);

        return "modules/flow/flowFormPreview";
    }

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "userPermission")
    public String userPermission(FlowForm flowForm, Model model) {
	    model.addAttribute("flowForm", flowForm);
	    model.addAttribute("selectIds", flowForm.getUserIds());
        return "modules/flow/flowFormPermission";
    }

    @RequiresPermissions("flowable:flowForm:edit")
    @RequestMapping(value = "saveUserPermission")
    @ResponseBody
    public String saveUserPermission(FlowForm flowForm) {
        if(Global.isDemoMode()){
            return renderResult(Global.FALSE, "演示模式，不允许操作！");
        }
        flowFormService.saveFormUser(flowForm);
        return renderResult(Global.TRUE, "保存成功");
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "common")
    public String common(Flow act, Model model) {

        String[] modelKeyVer = act.getProcDefId().split(":");

		// 获取流程实例对象
		if (act.getProcInsId() != null) {// 非发起流程
			ProcessInstance procIns = actTaskService.getProcIns(act.getProcInsId());
			if(procIns!=null) {
				act.setBusinessId(procIns.getBusinessKey());
			}else {
				HistoricProcessInstance history = actTaskService.getHistoryProcIns(act.getProcInsId());
				act.setBusinessId(history.getBusinessKey());
			}

            FormVersion formVersion = flowFormService.findFormVersion(act.getProcInsId());
            modelKeyVer[1] = String.valueOf(formVersion.getModelVersion());

            act.setHasUnAuditPassFlow(FlowableUtils.hasUnAuditPassFlow(act.getTaskId()));
        } else {// 发起流程
            DeModel deModel = deModelService.get(new DeModel("", modelKeyVer[0]));
            modelKeyVer[1] = String.valueOf(deModel.getVersion());

//            act.
        }
        act.setModelVersion(modelKeyVer[1]);

		// 获取流程表单
        FlowForm flowForm = flowFormService.getEntity(new FlowForm(modelKeyVer[0], modelKeyVer[1]));
        if (flowForm == null) {
            model.addAttribute("message", "请先去完成流程表单设计！");
            return "modules/flow/flowFormError";
        }
        act.setFormId(flowForm.getId());
        // 获取表单数据
        List<FormData> formDataList = null;
        if (StringUtils.isNotBlank(act.getProcInsId())) {
            formDataList = formDataService.findList(new FormData(flowForm.getId(), act.getProcInsId()));
        } else {
            formDataList = formDataService.findTempList(new FormData(flowForm.getId(), act.getProcDefKey(), UserUtils.getUser()));
        }

        // 获取数据权限信息
        List<TaskNode> taskNodeList = authorizeService.findList(new TaskNode(modelKeyVer[0], modelKeyVer[1]));
        if (taskNodeList == null) {
            model.addAttribute("message", "请先去完成表单字段权限设置！");
            return "modules/flow/flowFormError";
        }

        String taskDefKey;
        if (act.getStatus()!= null && (act.getStatus().equals("finish") || act.getStatus().equals("edit"))) {
            taskDefKey = act.getStatus();
        } else {
            taskDefKey = act.getTaskDefKey();
        }
        String formContent = FormUtils.parseForm(flowForm.getFormContent(), formDataList, taskNodeList, taskDefKey);

        model.addAttribute("formContent", formContent);
        model.addAttribute("act", act);

        String formKey = actTaskService.getFormKey(act.getProcDefId(), act.getTaskDefKey());
        if (StringUtils.isNotBlank(formKey)) {
            return formKey;
        }

        return "modules/flow/flowFormCommon";
    }


    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "saveForm")
    @ResponseBody
    public String saveForm(Flow act, HttpServletRequest request) {
        String[] modelKeyVer = act.getProcDefId().split(":");
        modelKeyVer[1] = act.getModelVersion();

        List<String> fieldList = authorizeService.findFieldByKeyVer(modelKeyVer[0], modelKeyVer[1]);

        Map<String, String> formFieldMap = new HashMap<>();
        for (String field : fieldList) {
            String val;
            if(field.equals("departments")){
                val = StringUtils.join(request.getParameterValues(field), ",");
            } else {
                val = request.getParameter(field);
            }
            formFieldMap.put(field, val);
        }

        // 发起流程
        if (StringUtils.isBlank(act.getBusinessId())) {
            FlowFormBusiness formBusiness = new FlowFormBusiness(act.getFormId());
            formBusiness.preInsert();

            Map<String, Object> variables = queryFlowVars(modelKeyVer[0], modelKeyVer[1], formFieldMap, act);
            String procIns = actTaskService.startProcess(modelKeyVer[0], formBusiness.getId(), variables);
            // 保存流程实例关联模型版本信息
            flowFormService.saveFormVersion(new FormVersion(procIns, modelKeyVer[1]));
            // 保存流程业务表
            formBusiness.setProcInsId(procIns);
            businessService.insert(formBusiness);

            // 保存流程字段数据
            for (Map.Entry<String, String> entry : formFieldMap.entrySet()) {
                FormData formData = new FormData(act.getFormId(), procIns, entry.getKey());
                if (FormUtils.shortField(entry.getValue())) {
                    formData.setFieldValue(entry.getValue());
                } else {
                    formData.setFieldLargeValue(entry.getValue());
                }

                formDataService.save(formData);
            }

            // 更新附件数据，更新mainId字段值为 procIns
            if (StringUtils.isNotBlank(act.getFileIds())) {
                List<String> fileIds = Arrays.asList(act.getFileIds().split(","));
                fileService.batchUpdate(fileIds, procIns);
            }

            // 删除暂存流程数据
            formDataService.deleteTemp(new FormData("", modelKeyVer[0], UserUtils.getUser()));

            logger.debug("流程已启动，流程ID："+ procIns);
            return renderResult(Global.TRUE, "流程启动成功");

        } else{

            List<FormData> formDataList = formDataService.findList(new FormData(act.getFormId(), act.getProcInsId()));
            for (FormData formData : formDataList) {
                String tmp = formFieldMap.get(formData.getFieldName());
                if (FormUtils.shortField(tmp)) {
                    formData.setFieldValue(tmp);
                } else {
                    formData.setFieldLargeValue(tmp);
                }

                formDataService.save(formData);
            }

            // 更新附件数据，更新mainId字段值为 procIns
            if (StringUtils.isNotBlank(act.getFileIds())) {
                List<String> fileIds = Arrays.asList(act.getFileIds().split(","));
                fileService.batchUpdate(fileIds, act.getProcInsId());
            }

            Map<String, Object> variables = queryFlowVars(modelKeyVer[0], modelKeyVer[1], formFieldMap, act);
            // 完成流程任务
            variables.put("auditPass", act.isPass());



            actTaskService.complete(act.getTaskId(), act.getProcInsId(), StringUtils.isBlank(act.getComment())?(act.isPass()?"同意":"驳回"):act.getComment(), variables);

            return renderResult(Global.TRUE, "操作成功");
        }
    }


    private Map<String, Object> queryFlowVars(String modelKey, String modelVer, Map<String, String> formFieldMap, Flow act) {
        Map<String, Object> variables = Maps.newHashMap();
        List<TaskNode> varList = varsService.findList(new TaskNode(modelKey, modelVer));
        for (TaskNode node : varList) {
            if (node.getVarName().equals("auditPass")) {
                variables.put(node.getVarName(), act.isPass());
            } else {
                variables.put(node.getVarName(), formFieldMap.get(node.getFieldName()));
            }
        }

        if (formFieldMap.get("task_asignee") != null && StringUtils.isNotBlank(formFieldMap.get("task_asignee"))) {
            variables.put("leaderName", formFieldMap.get("task_asignee").split(",")[1]);
        } else {
            if (StringUtils.isNotBlank(act.getProcInsId()) && StringUtils.isNotBlank(act.getTaskId())) {
                String taskAsignee = FlowableUtils.nextTaskAsignee(act.getProcInsId(), act.getTaskId(), variables);
                variables.put("leaderName", taskAsignee);
            }
        }

        return variables;
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "checkFlowExit")
    @ResponseBody
    public String checkFlowExit(String procDefKey) {
        List<ProcessInstance> exitList = actTaskService.getProcInsByKey(UserUtils.getUser().getLoginName(), procDefKey);
        if (exitList == null || exitList.size() <= 0) {
            return renderResult(Global.FALSE, "不存在未完成流程");
        } else {
            return renderResult(Global.TRUE, "存在未完成流程");
        }
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "hasTemp")
    @ResponseBody
    public String hasTemp(String procDefKey) {
        List<FormData> formDataList = formDataService.findTempList(new FormData("", procDefKey, UserUtils.getUser()));
        if (formDataList == null || formDataList.size() <= 0) {
            return renderResult(Global.FALSE, "没有缓存数据");
        } else {
            return renderResult(Global.TRUE, "存在缓存数据");
        }
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "delTemp")
    @ResponseBody
    public String delTemp(String procDefKey) {
        formDataService.deleteTemp(new FormData("", procDefKey, UserUtils.getUser()));
        return renderResult(Global.TRUE, "删除缓存数据");
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "saveFormTemp")
    @ResponseBody
    public String saveFormTemp(Flow act, HttpServletRequest request) {

        String[] modelKeyVer = act.getProcDefId().split(":");
        modelKeyVer[1] = act.getModelVersion();

        List<String> fieldList = authorizeService.findFieldByKeyVer(modelKeyVer[0], modelKeyVer[1]);

        Map<String, String> formFieldMap = new HashMap<>();
        for (String field : fieldList) {
            formFieldMap.put(field, request.getParameter(field));
        }

        // 保存流程字段数据
        for (Map.Entry<String, String> entry : formFieldMap.entrySet()) {
            FormData formData = new FormData();
            formData.setFormId(act.getFormId());
            formData.setProcDefKey(modelKeyVer[0]);
            formData.setCreateBy(UserUtils.getUser());
            formData.setFieldName(entry.getKey());

            if (FormUtils.shortField(entry.getValue())) {
                formData.setFieldValue(entry.getValue());
            } else {
                formData.setFieldLargeValue(entry.getValue());
            }

            formDataService.saveTemp(formData);
        }

        return renderResult(Global.TRUE, "自动保存成功");
    }

    @RequiresPermissions("flowable:flowForm:view")
    @RequestMapping(value = "updateFormData")
    @ResponseBody
    public String updateFormData(Flow act, HttpServletRequest request) {
        String[] modelKeyVer = act.getProcDefId().split(":");
        modelKeyVer[1] = act.getModelVersion();

        List<String> fieldList = authorizeService.findFieldByKeyVer(modelKeyVer[0], modelKeyVer[1]);

        Map<String, String> formFieldMap = new HashMap<>();
        for (String field : fieldList) {
            formFieldMap.put(field, request.getParameter(field));
        }

        List<FormData> formDataList = formDataService.findList(new FormData(act.getFormId(), act.getProcInsId()));
        for (FormData formData : formDataList) {
            String tmp = formFieldMap.get(formData.getFieldName());
            if (FormUtils.shortField(tmp)) {
                formData.setFieldValue(tmp);
            } else {
                formData.setFieldLargeValue(tmp);
            }

            formDataService.save(formData);
        }

        return renderResult(Global.TRUE, "修改成功");
    }
}